home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Bitmap Libraries 2.0 / Examples / PaintBucket / PaintBucket.c < prev    next >
Text File  |  1996-02-27  |  11KB  |  450 lines

  1. /* File Example.c Copyright (C) 1996 by John R. Montbriand.  All Rights Reserved. */
  2.  
  3. /* File Example.c
  4.  
  5.     Copyright (C) 1996 by John Montbriand.  All Rights Reserved.
  6.     
  7.     Distribute freely in areas where the laws of copyright apply.
  8.     
  9.     Use at your own risk.
  10.     
  11.     Do not distribute modified copies.
  12.     
  13.     These various BitMap libraries and examples are for free!
  14.     
  15.     See the accompanying file BitMap.txt for details.
  16.     
  17. */
  18.  
  19. /* written in Geneva 9, tabs at 4 */
  20.  
  21. /* •••••••••••••••••••••• INCLUDES •••••••••••••••••••••• */
  22.  
  23. #include <Types.h>
  24. #include <QuickDraw.h>
  25. #include <Fonts.h>
  26. #include <Windows.h>
  27. #include <Menus.h>
  28. #include <TextEdit.h>
  29. #include <Dialogs.h>
  30. #include <AppleEvents.h>
  31. #include <TextUtils.h>
  32. #include <OSUtils.h>
  33. #include <ToolUtils.h>
  34. #include <Desk.h>
  35. #include <Memory.h>
  36. #include <Errors.h>
  37. #include <Gestalt.h>
  38. #include <Traps.h>
  39. #include <SegLoad.h>
  40.  
  41. #include "BitMap.h"
  42.  
  43. /* •••••••••••••••••••••• CONSTANTS •••••••••••••••••••••• */
  44.  
  45. #define kAboutBoxID 128
  46. #define kErrorBoxID 129
  47. #define kMainWindID 128
  48. #define kMenuBarID 128
  49.  
  50. #define mApple 128
  51. #define iAbout 1
  52. #define iAccessoryOne 3
  53.  
  54. #define mFile 129
  55. #define iQuit 1
  56.  
  57. #define mEdit 130
  58. #define iUndo 1
  59. #define iCut 3
  60. #define iCopy 4
  61. #define iPaste 5
  62. #define iClear 6
  63.  
  64. /* •••••••••••••••••••••• GLOBALS •••••••••••••••••••••• */
  65.  
  66. Boolean PROGRAM_RUNNING = true;
  67. Boolean PROGRAM_FRONT = true;
  68. Boolean HAS_APPLEEVENTS = false;
  69. Boolean HAS_WAITNEXTEVENT = false;
  70.  
  71. QDGlobals    qd;
  72.  
  73. DialogPtr gABOUTBOX = NULL;
  74. WindowPtr gMAIN_WINDOW = NULL;
  75.  
  76.  
  77. /* •••••••••••••••••••••• ERROR HANDLER •••••••••••••••••••••• */
  78.  
  79. /* Terminate, displays an error box containing the error number and then terminates
  80.     the application. */
  81. void Terminate(OSErr err) {
  82.     Str255 s;
  83.     NumToString(err, s);
  84.     ParamText(s, NULL, NULL, NULL);
  85.     Alert(kErrorBoxID, NULL);
  86.     ExitToShell();
  87. }
  88.  
  89. /* •••••••••••••••••••••• THE EXAMPLE PART •••••••••••••••••••••• */
  90. /* NOTE:  all of the example code to do with bitmaps is included in this part of the
  91. program.  The rest of the program has to do with the usual things that go into
  92. applications.  */
  93.  
  94. Rect gBounds;
  95. CursHandle gPaintCursor;
  96. BitMap *pic_bits, *mask_bits;
  97.  
  98.  
  99. /*DrawWindowContents is called in response to every update event for the main
  100.     window.  this is the part where we do drawing in the bitmaps */
  101. void DrawWindowContents(WindowPtr wp) {
  102.     if (mask_bits == NULL) {
  103.     
  104.             /* no mask, just draw the image... */
  105.         PlotBitMap(pic_bits, 5, 5, srcCopy);
  106.         
  107.     } else {
  108.         BitMap *gray_mask, *drawn_bits;
  109.         BitMapPort* bmp;
  110.         
  111.             /* calculate the masks */
  112.         gray_mask = NULL;
  113.         drawn_bits = NULL;
  114.         
  115.             /* calculate the painted area in gray */
  116.         gray_mask = DuplicateBitMap(mask_bits);
  117.         if (gray_mask == NULL) goto bail;
  118.         WithBitMap(gray_mask, bmp) {
  119.             PenMode(patBic);
  120.             PenPat(&qd.gray);
  121.             PaintRect(&gray_mask->bounds);
  122.         }
  123.         
  124.             /* add the painted area to the drawn area */
  125.         drawn_bits = BitMapOR(gray_mask, pic_bits);
  126.         if (drawn_bits == NULL) goto bail;
  127.         
  128.             /* draw the image */
  129.         PlotBitMap(drawn_bits, 5, 5, srcCopy);
  130.         
  131.     bail:
  132.         if (gray_mask != NULL) KillBitMap(gray_mask);
  133.         if (drawn_bits != NULL) KillBitMap(drawn_bits);
  134.     }
  135. }
  136.  
  137.  
  138. /*ClickWindowContents is called every time a mouse down event occurs in the
  139.     main program window allowing for some interaction. Here, we track the
  140.     mouse re-drawing the window appropriately as the mouse is dragged
  141.     accross the window*/
  142. void ClickWindowContents(WindowPtr wp, Point where) {
  143.     Point location, lastpos;
  144.     BitMap* next_mask;
  145.     location = where;
  146.     SetPt(&lastpos, 0, 0);
  147.     do {
  148.         if (PtInRect(location, &gBounds) && !EqualPt(lastpos, location)) {
  149.             lastpos = location;
  150.             
  151.                 /* map the point from the drawn position, to the image */
  152.             MapPt(&location, &gBounds, &pic_bits->bounds);
  153.             
  154.                 /* make a new mask */
  155.             next_mask = PaintBucketBitMap(pic_bits, location.h, location.v);
  156.             if (next_mask == NULL) Terminate(memFullErr);
  157.                 
  158.                 /* redraw the window only if a change occured */
  159.             if (!EqualBitMaps(mask_bits, next_mask)) {
  160.                     
  161.                     /* replace the old mask */
  162.                 if (mask_bits != NULL)
  163.                     KillBitMap(mask_bits);
  164.                 mask_bits = next_mask;
  165.                 
  166.                     /* redraw the window */
  167.                 DrawWindowContents(wp);
  168.                 
  169.             } else KillBitMap(next_mask);
  170.  
  171.         }
  172.         GetMouse(&location);
  173.     } while (StillDown());
  174. }
  175.  
  176.  
  177. /* InitExample is called at program startup after the main window has been
  178.     created to allow the example to set itself up.  I put it here so all the example
  179.     code would be together in one section. */
  180. OSErr InitExample(WindowPtr wp) {
  181.     PicHandle pic;
  182.     OSErr err;
  183.     
  184.         /* initial state */
  185.     pic_bits = NULL;
  186.     mask_bits = NULL;
  187.  
  188.         /* get the resources */
  189.     gPaintCursor = GetCursor(128);
  190.     if (gPaintCursor == NULL) { err = resNotFound; goto bail; }
  191.     pic = GetPicture(129);
  192.     if (pic == NULL) { err = resNotFound; goto bail; }
  193.     
  194.         /* make the bitmap */
  195.     pic_bits = PICTToBitMap(pic);
  196.     if (pic == NULL) { err = memFullErr; goto bail; }
  197.  
  198.         /* adjust the window size */
  199.     SizeWindow(wp, pic_bits->bounds.right+10, pic_bits->bounds.bottom+10, true);
  200.     gBounds = pic_bits->bounds;
  201.     OffsetRect(&gBounds, 5, 5);
  202.  
  203.         /* done */
  204.     return noErr;
  205. bail:
  206.     if (pic_bits != NULL) KillBitMap(pic_bits);
  207.     return err;
  208. }
  209.  
  210.  
  211. /* AdjustCursor is called once every time through the main loop so we
  212.     can set up the cursor to look like a paint bucket when it's over the
  213.     image. */
  214. void AdjustCursor(void) {
  215.     if (FrontWindow() == gMAIN_WINDOW) {
  216.         Point mouseLoc;
  217.         SetPort(gMAIN_WINDOW);
  218.         GetMouse(&mouseLoc);
  219.         if (PtInRect(mouseLoc, &gBounds)) {
  220.             SetCursor(*gPaintCursor);
  221.             return;
  222.         }
  223.     }
  224.     InitCursor();
  225. }
  226.  
  227. /* •••••••••••••••••••••• MENU COMMANDS •••••••••••••••••••••• */
  228.  
  229. /* HandleMenuCommand is called after MenuKey or MenuSelect to handle the processing
  230.      of menu commands.  Here there aren't too many, just the standard ones */
  231. void HandleMenuCommand(short menu, short item) {
  232.     if (menu == mApple) {
  233.         if (item == iAbout) {
  234.             if (gABOUTBOX != NULL)
  235.                 SelectWindow(gABOUTBOX);
  236.             else gABOUTBOX = GetNewDialog(kAboutBoxID, NULL, (WindowPtr) (-1));
  237.         } else if (item >= iAccessoryOne) {
  238.             Str255 itemString;
  239.             GetItem(GetMHandle(menu), item, itemString);
  240.             OpenDeskAcc(itemString);
  241.         }
  242.     } else if (menu == mFile) {
  243.         switch (item) {
  244.             case iQuit:
  245.                 PROGRAM_RUNNING = false;
  246.                 break;
  247.         }
  248.     } else if (menu == mEdit) {
  249.         SystemEdit(item-1);
  250.     }
  251.     HiliteMenu(0);
  252. }
  253.  
  254. /* MenuPreflightCheck is called immediately before MenuKey or MenuSelect.  In your
  255.     application you would use this routine to appropriately enable or disable different
  256.     commands depending on what can be done at the time of the mouse click or key
  257.     command. */
  258. void MenuPreflightCheck(void) {
  259.     /* none here*/
  260. }
  261.  
  262.  
  263. /* •••••••••••••••••••••• EVENT HANDLING •••••••••••••••••••••• */
  264.  
  265. /* HandleMouseDownEvent is called to process mouse down events */
  266. void HandleMouseDownEvent(EventRecord *ev) {
  267.     WindowPtr target;
  268.     switch ( FindWindow(ev->where, &target) ) {
  269.         case inDesk:
  270.             break;
  271.         case inSysWindow:
  272.             SystemClick(ev, target);
  273.             break;
  274.         case inContent:
  275.             if (target != FrontWindow())
  276.                 SelectWindow(target);
  277.             else if (target == gMAIN_WINDOW) {
  278.                 Point where;
  279.                 where = ev->where;
  280.                 SetPort(target);
  281.                 GlobalToLocal(&where);
  282.                 ClickWindowContents(target, where);
  283.             }
  284.             break;
  285.         case inDrag:
  286.             {    Rect r = qd.screenBits.bounds;
  287.                 if (target != FrontWindow()) SelectWindow(target);
  288.                 SetPort(target);
  289.                 InsetRect(&r, 4, 4);
  290.                 r.top += 20;
  291.                 DragWindow(target, ev->where, &r);
  292.             }
  293.             break;
  294.         case inGoAway:
  295.             if (TrackGoAway(target, ev->where)) {
  296.                 if (target == gABOUTBOX) {
  297.                     DisposeDialog(gABOUTBOX);
  298.                     gABOUTBOX = NULL;
  299.                 } else PROGRAM_RUNNING = false;
  300.             }
  301.             break;
  302.         case inMenuBar:
  303.             {    long mnRes;
  304.                 MenuPreflightCheck();
  305.                 if (HiWord(mnRes = MenuSelect(ev->where)) != 0)
  306.                     HandleMenuCommand(HiWord(mnRes), LoWord(mnRes));
  307.             }
  308.             break;
  309.     }
  310. }
  311.  
  312. /* SystemSwapTask can be called from anywhere in your application.  basically it collects
  313.     events and gives the system time to do its thing. */
  314. void SystemSwapTask(void) {
  315.     EventRecord ev;
  316.     
  317.         /* get the next event */
  318.     if (HAS_WAITNEXTEVENT) {
  319.         if (!WaitNextEvent(everyEvent, &ev, 0, NULL)) ev.what = nullEvent;
  320.     } else {
  321.         if (!GetNextEvent(everyEvent, &ev)) ev.what = nullEvent;
  322.         SystemTask();
  323.     }
  324.     
  325.     AdjustCursor();
  326.     
  327.     if ((ev.what == keyDown || ev.what == autoKey) && (ev.modifiers & cmdKey) != 0) {
  328.         long mnRes;
  329.         MenuPreflightCheck();
  330.         if (HiWord(mnRes = MenuKey((char) (ev.message & charCodeMask))) != 0)
  331.             HandleMenuCommand(HiWord(mnRes), LoWord(mnRes));
  332.     } else if (IsDialogEvent(&ev)) {
  333.         DialogPtr theDialog;
  334.         short itemHit;
  335.         DialogSelect(&ev, &theDialog, &itemHit);
  336.     } else if (ev.what == mouseDown) {
  337.         HandleMouseDownEvent(&ev);
  338.     } else if (ev.what == updateEvt) {
  339.         WindowPtr wp;
  340.         wp = (WindowPtr) ev.message;
  341.         SetPort(wp);
  342.         BeginUpdate(wp);
  343.         DrawWindowContents(wp);
  344.         EndUpdate(wp);
  345.     } else if (ev.what == kHighLevelEvent) {
  346.         if (HAS_APPLEEVENTS)
  347.             AEProcessAppleEvent(&ev);
  348.     } else if (ev.what == osEvt) {
  349.         if (((ev.message >> 24) & 0x0FF) == suspendResumeMessage)
  350.             PROGRAM_FRONT = (ev.message & resumeFlag) != 0;
  351.     }
  352.     
  353. }
  354.  
  355.  
  356. /* •••••••••••••••••••••• APPLE EVENTS •••••••••••••••••••••• */
  357.  
  358. /* QuitEventHandler called for quit apple events.  all we do here is set the running
  359.     flag to false */
  360. pascal OSErr QuitEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, long refcon) {
  361.     DescType retType;
  362.     Size actSize;
  363.     OSErr err;
  364.     err = AEGetAttributePtr(appleEvt, keyMissedKeywordAttr, typeWildCard, &retType, NULL, 0, &actSize);
  365.     if (err == errAEDescNotFound) {
  366.         PROGRAM_RUNNING = false;
  367.         return noErr;
  368.     } else if (err == noErr)
  369.         return errAEEventNotHandled;
  370.     else return err;
  371. }
  372.  
  373.  
  374. /* •••••••••••••••••••••• TEST FOR TRAPS •••••••••••••••••••••• */
  375.  
  376. unsigned short NumToolboxTraps(void) {
  377.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  378.         return 0x0200;
  379.     else return 0x0400;
  380. }
  381.  
  382. TrapType FindTrapType(unsigned short theTrap) {
  383.     if (theTrap & 0x0800)
  384.         return ToolTrap;
  385.     else return OSTrap;
  386. }
  387.  
  388. Boolean TrapAvailable(unsigned short theTrap) {
  389.     unsigned short localTrap = theTrap;
  390.     TrapType tType = FindTrapType(localTrap);
  391.     if ( tType == ToolTrap ) {
  392.         localTrap &= 0x07FF;
  393.         if ( localTrap >= NumToolboxTraps() )
  394.             localTrap = _Unimplemented;
  395.     }
  396.     return NGetTrapAddress(localTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap);
  397. }
  398.  
  399.  
  400. /* •••••••••••••••••••••• MAIN PROGRAM •••••••••••••••••••••• */
  401.  
  402. void main(void) {
  403.     OSErr err;
  404.     long response;
  405.  
  406.         /* determine features of the machine */
  407.     if (Gestalt(gestaltAppleEventsAttr, &response) != noErr) response = 0;
  408.     HAS_APPLEEVENTS = ((response & (1<<gestaltAppleEventsPresent)) != 0);
  409.     HAS_WAITNEXTEVENT = TrapAvailable(_WaitNextEvent);
  410.     
  411.         /* initialize the toolbox, etc.. */
  412.     SetApplLimit( GetApplLimit() - (8*1024) );
  413.     MaxApplZone();
  414.     InitGraf(&qd.thePort);
  415.     InitFonts();
  416.     InitWindows();
  417.     TEInit();
  418.     InitMenus();
  419.     InitDialogs(NULL);
  420.     InitCursor();
  421.     if (HAS_APPLEEVENTS) {
  422.         err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  423.                     NewAEEventHandlerProc(QuitEventHandler), 0, false);
  424.         if (err != noErr) goto bail;
  425.     }
  426.     SetMenuBar(GetNewMBar(kMenuBarID));
  427.     AddResMenu(GetMHandle(mApple), 'DRVR');
  428.     DrawMenuBar();
  429.     gMAIN_WINDOW = GetNewWindow(kMainWindID, NULL, (WindowPtr) (-1));
  430.     SetPort(gMAIN_WINDOW);
  431.     err = InitExample(gMAIN_WINDOW);
  432.  
  433.         /* set up some globals */
  434.     PROGRAM_RUNNING = true;
  435.     PROGRAM_FRONT = true;
  436.     
  437.         /* loop until PROGRAM_RUNNING is false */
  438.     while (PROGRAM_RUNNING)
  439.         SystemSwapTask();
  440.     
  441.     return;
  442.     
  443. bail:
  444.     Terminate(err);
  445. }
  446.  
  447.  
  448. /* end File BitMap.c */
  449.  
  450.